/*******************************************************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Nicolas DAURES
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *******************************************************************************************************************/


/****************************************************************
 * Scene Node
 ****************************************************************/

// Scene node with a parent node and a child node array
function SceneNode()
{
	//=======================
	// Fields
	//=======================

    this.m_ParentNode =			null;
    this.m_aChildNodes = 		new Array();
    this.m_v2Pos = 				new b2Vec2(0, 0);
    this.m_v2Scale = 			new b2Vec2(1, 1);
    this.m_fOrientation =		0;
    this.m_v2WorldPos =			new b2Vec2(0, 0);
    this.m_v2WorldScale = 		new b2Vec2(1, 1);
    this.m_fWorldOrientation =	0;
};

//=======================
// Accessors
//=======================

SceneNode.prototype.getParentNode = function()
{
    return this.m_ParentNode;
}

SceneNode.prototype.getChildNodes = function()
{
    return this.m_aChildNodes;
}

SceneNode.prototype.getPosition = function()
{
    return this.m_v2Pos;
}

SceneNode.prototype.setPosition = function(a_v2Pos)
{
    this.m_v2Pos = a_v2Pos;
}

SceneNode.prototype.getScale = function()
{
    return this.m_v2Scale;
}

SceneNode.prototype.setScale = function(a_v2Scale)
{
    this.m_v2Scale = a_v2Scale;
}

SceneNode.prototype.getOrientation = function()
{
    return this.m_fOrientation;
}

SceneNode.prototype.setOrientation = function(a_fOrientation)
{
    this.m_fOrientation = a_fOrientation;
}

SceneNode.prototype.getWorldPosition = function()
{
    return this.m_v2WorldPos;
}

SceneNode.prototype.getWorldScale = function()
{
    return this.m_v2WorldScale;
}

SceneNode.prototype.getWorldOrientation = function()
{
    return this.m_fWorldOrientation;
}


//=======================
// Operations
//=======================

SceneNode.prototype.update = function()
{
    if (this.m_ParentNode != null)
    {
        this.m_v2WorldPos.x = this.m_ParentNode.m_v2Pos.x + this.m_v2Pos.x;
        this.m_v2WorldPos.y = this.m_ParentNode.m_v2Pos.y + this.m_v2Pos.y;
        this.m_v2WorldScale.x = this.m_ParentNode.m_v2Scale.x * this.m_v2Scale.x;
        this.m_v2WorldScale.y = this.m_ParentNode.m_v2Scale.y * this.m_v2Scale.y;
        this.m_fWorldOrientation = this.m_ParentNode.m_fOrientation + this.m_fOrientation;
    }
    else
    {
        this.m_v2WorldPos.x = this.m_v2Pos.x;
        this.m_v2WorldPos.y = this.m_v2Pos.y;
        this.m_v2WorldScale.x = this.m_v2Scale.x;
        this.m_v2WorldScale.y = this.m_v2Scale.y;
        this.m_fWorldOrientation = this.m_fOrientation;
    }

    for (var i = 0; i < this.m_aChildNodes.length; i++)
    {
        this.m_aChildNodes[i].update();
    }
}

SceneNode.prototype.attachSceneNode = function(a_SceneNode)
{
    this.m_aChildNodes.push(a_SceneNode);
    a_SceneNode.m_ParentNode = this;
}

SceneNode.prototype.detachSceneNode = function(a_SceneNode)
{
    for (var i = 0; i < this.m_aChildNodes.length; i++)
    {
        if (this.m_aChildNodes[i] == a_SceneNode)
        {
            this.m_aChildNodes.splice(i, 1);
            a_SceneNode.m_ParentNode = null;
        }
    }
}


/****************************************************************
 * Scene Engine
 ****************************************************************/

// Scene engine with a root scene node
function SceneEngine()
{
	//=======================
	// Fields
	//=======================

	this.m_RootSceneNode =	new SceneNode();
}


//=======================
// Accessors
//=======================

SceneEngine.prototype.getRootSceneNode = function()
{
    return this.m_RootSceneNode;
}


//=======================
// Operations
//=======================

SceneEngine.prototype.update = function()
{
    this.m_RootSceneNode.update();
}

SceneEngine.m_Instance = null;
SceneEngine.getInstance = function()
{  
    if (this.m_Instance == null)
    {  
		this.m_Instance = new SceneEngine();  
    }  

    return this.m_Instance;  
}


/****************************************************************
 * Auto Move Camera
 ****************************************************************/

// Auto-move camera behavior
function AutoMoveCamera()
{
	//=======================
	// Fields
	//=======================

    this.m_v2Speed = new b2Vec2(20, 0);
};


//=======================
// Operations
//=======================

AutoMoveCamera.prototype.update = function()
{
    var fdt = TimeEngine.getInstance().m_fDeltaTime;
    var v2CamPos = CameraEngine.getInstance().m_SceneNode.m_v2Pos;
    v2CamPos.x += this.m_v2Speed.x * fdt;
    v2CamPos.y += this.m_v2Speed.y * fdt;
}


/****************************************************************
 * Camera Engine
 ****************************************************************/

// Camera manager
function CameraEngine()
{
	//=======================
	// Fields
	//=======================

	this.m_SceneNode =		new SceneNode();
	this.m_CameraBehavior =	null;

	SceneEngine.getInstance().getRootSceneNode().attachSceneNode(this.m_SceneNode);
}


//=======================
// Operations
//=======================

CameraEngine.prototype.update = function()
{
    if (this.m_CameraBehavior != null)
    {
        this.m_CameraBehavior.update();
    }
}

CameraEngine.m_Instance = null;
CameraEngine.getInstance = function()
{  
    if (this.m_Instance == null)
    {  
		this.m_Instance = new CameraEngine();  
    }  

    return this.m_Instance;  
}
